﻿<!--
/*#
# Copyright 2012 Google Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# This code is not supported by Google
#
*/

Sample classic ASP code for Google Commerce Search to submit ShoppingAPI-Search queries 
 then parse out the responses for display. 
 Shows additive filtering and page navigation.  

 If you site has Search As You type enabled, this code will automatically show
 the suggestions.
 
 >>> This code is NOT designed for production deployment and has not been 
 throughly tested.  It should only be used to understand GCS features.  <<<


 Usage:
  
  Edit the file and specify the GCS instance ID (cx) and the API key you're 
  using.

-->


<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
    <head>
    <title>GCS Search</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
        <!-- FOR SAYT -->   
        <link rel="stylesheet" href="http://www.google.com/cse/style/commerce_sayt.css" type="text/css" media="screen" />
        <script src="http://www.google.com/jsapi" type="text/javascript"></script>
        <script src="//ajax.googleapis.com/ajax/libs/googleapis/0.0.4/googleapis.min.js" type="text/javascript"></script>
        <script src="http://www.google.com/cse/intl/en-US/sayt.js" type="text/javascript"></script>

        <!-- FOR UI -->  
        <link href="http://www.google.com/css/go.css" type="text/css" rel="stylesheet"/>  

             <style type="text/css">
		        body {
		            background-color: #FFFFFF;
		            color: #000000;
		            font-family: Helvetica,Arial,sans-serif;
		            font-size: small;
		            margin: 3px 8px;
		        }
		        body {
		            max-width: 1000px;
		            padding: 15px;
		        }
		        html {
		            height: auto;
		            margin: 0;
		            padding: 0;
		        }		
		        table {
	            border-collapse: collapse;
	            border-spacing: 0;
		        }
	        </style>

	
	        <script type="text/javascript">
	            // Google Analytics integration
	            // Enter you analytics ID here
	            var _gaq = _gaq || [];
	            _gaq.push(['_setAccount', 'YOUR ANALYTICS ID']);
	            _gaq.push(['_trackPageview']);

	            (function () {
	                var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
	                ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
	                var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
	            })();
	        </script>


	        <script language="javascript">

	            //from http://blog.movalog.com/a/javascript-toggle-visibility/
	            // some script to toggle the visibility of the per-item details
	            var state = 'none';
	            function showhide(id, productID) {
	                var e = document.getElementById(id);
	                if (e.style.display == 'block')
	                    e.style.display = 'none';
	                else
	                    e.style.display = 'block';
	                sendProductID(productID);
	            }

	            //used to simulate sending google search requestID and item click
	            //simulation...normally this is done only when someone clicks on
	            //a search result	
	            function sendProductID(productID) {
	                _gaq.push(['_setCustomVar', 4, 'GCS_ProductID', productID, 3]);
	                _gaq.push(['_trackPageview']);
	            }
	            function sendRequestID(requestID) {
	                _gaq.push(['_setCustomVar', 3, 'GCS_RequestID', requestID, 3]);
	                _gaq.push(['_trackPageview']);
	            }

	            function initialize()
	            { }
	        </script>	
    </head>    

    <%
      // some variables:

       dim outbound_shopping         //  outbound_shopping:  The outbound Shopping API Call
       dim requestID                 // the parsed ShoppingAPI requestID
       dim remove_filters            // Variable to hold the restrictBy filters to remove for navigation
       dim totalResults
       dim page_nav               
       dim html_attributes            // Variable to hold the HTML to display for the attribute navigation
       dim html_results               // Variable to hold the HTML to display the results
       dim TOTAL_PAGES_TO_SHOW
        
       dim q 
       dim startIndex
       dim restrictBy
       dim orderby 
       dim sortorder 
       dim time_taken     

    dim cx 
    dim devkey 
    dim  language 
    dim country 
    devkey = "YOUR_KEY"

    cx = "YOUR CX"
    country = "us"
    language = "en" 

    Response.CodePage = 65001
    Response.CharSet = "utf-8"

    q = Request.QueryString("q")
    startIndex = Request.QueryString("startIndex")
    restrictBy = Request.QueryString("restrictBy")

    // START:  the following section extracts the browser-->IIS servers &restrictBy= parameter
    // For simplicity in parsing, browser-->IIS has the &restrictBy=name1=value1,name2=value2
    // the value1,value2 has the following replacements: &--><>  ,-->~

    dim drestrictBy
    if (restrictBy <> "") then
        drestrictBy = ""
        dim akey
        dim avalue
        // the inbound restrictBy= from the browser looks could look like
        //  restrictBy=category%20name(text)=Us%20State%20<>%20Town%20Views,price=[0~5.0)
        // which needs to get translated to the ShoppingAPI as:
        // &restrictBy=category name(text)=Us State & Town Views,price=[0,5.0)
        // NOTE: the attribute value is just encoded.
        attribute_list = split(restrictBy,",")
        For i = 0 To ubound(attribute_list)
           attrib = attribute_list(i)
           a = split(attrib,"=")
           akey = a(0)
           avalue = escapeShoppingAPI(DEC(a(1)))
           if (drestrictBy <> "") then
             drestrictBy = drestrictBy + "," + akey + "=" + avalue
           else
             drestrictBy = "&restrictBy=" + akey + "=" + avalue
           end if
        next                            
    else
        drestrictBy = ""
    end if
    // END 


   // Finds and sets the startIndex 
   Dim in_start_index 
   in_start_index =  Request.QueryString("startIndex")
   if (in_start_index = "") then
	startIndex = "&startIndex=1"
   else
     startIndex = "&startIndex=" + in_start_index
   End if

   // encodes the query
   if (q <> "") then
    q = "&q=" +  Server.URLEncode(q)
   end if

   // Now we have the query, startindex and the restricts in a format we can use
   // create a shoppingAPI call and send it on its way.
    dim shopping_base_query 
    shopping_base_query = "https://www.googleapis.com/shopping/search/v1/cx:" + cx + "/products?facets.enabled=true&country=" + country + "&maxResults=10&facets.useGcsConfig=true&facets.discover=20:10&alt=atom"
    response.CharSet = "UTF-8"
    set xmlDoc = createObject("MSXML2.DOMDocument")
    xmlDoc.async = False
    xmlDoc.setProperty "ServerHTTPRequest", true
    outbound_shopping = shopping_base_query + "&key=" + devkey + (startIndex + drestrictBy + q)
    //Response.Write outbound_shopping
    xmlDoc.load(outbound_shopping)

    // with the response, parse out the requestID and number of results
    requestID = xmlDoc.selectSingleNode("//feed/s:requestId").text
    totalResults = xmlDoc.selectSingleNode("//feed/openSearch:totalResults").text     

    // calculate the number of pages (limited to 10)
    dim num_pages
    num_pages = Round(Clng(totalResults)/10)
    TOTAL_PAGES_TO_SHOW = 10

    dim start_index
    start_index = 1
    if (num_pages > TOTAL_PAGES_TO_SHOW) then
        num_pages = TOTAL_PAGES_TO_SHOW
    end if

    // for each page, recreate the exact inbound query but only
    // change the 'startIndex' value
    For jj = 0 to num_pages -1
      dim ret_qstr
      ret_qstr = ""
      for each ji in Request.QueryString
        dim key
        dim value
        key = ji
        value = Request.QueryString(ji)
        if (key <> "startIndex") then
          ret_qstr = ret_qstr + key + "=" +  value + "&"
        End if
	  Next

      dim page_url
      page_url = ret_qstr + "startIndex=" + Cstr(start_index)
      dim pnum 
      pnum = jj +1
      if (totalResults <> "0") then
         page_nav = page_nav + "<a href='gcs.asp?" + page_url + "'>" + Cstr(pnum) + "</a>&nbsp;&nbsp;"
      end if
         start_index =  start_index + 10
      Next

    // If you wanted to parse out the spelling suggestions and promtions
      set xcorrection = xmlDoc.selectNodes("//feed/s:spelling/s:suggestion")
      set xpromotions = xmlDoc.selectNodes("//feed/s:promotions/s:promotion")


    // now extract out the query so that we can create a filter on it.
    // this just to display the query term as a 'remove filter'
    // extract the query and recreate the inbound request from the browser exactly with every parameter
    // *except* the query
	    if (Request.QueryString("q") <> "") then
		    dim qstr_without_q 
            qstr_without_q = ""
	        for each ji in Request.QueryString
		        dim fkey
                dim fvalue
                fkey = ji
                fvalue = Request.QueryString(ji)
                if (fkey <> "q" AND fkey <> "startIndex") then
                    if (qstr_without_q = "") then
    			        qstr_without_q = fkey + "=" + fvalue
                    else
	    		        qstr_without_q = qstr_without_q + "&" + fkey + "=" + fvalue
                    end if 
                End if
	        Next
   		    remove_filters = remove_filters + "<a href='gcs.asp?" + qstr_without_q + "'>" +  Request.QueryString("q") + "</a>&nbsp;&nbsp;&nbsp;"
	    End if

    // now it gets more complicated because we want to create the 'remove filters' for the attributes
    // filtered on earlier.
    // that is, if a user filters on restrictBy=color(text)=blue,brand=google
    // then we want to make two 'remove filters: one for color and the other for brand:
    // for color, it'd look like <a href="gcs.jsp?restrictBy=brand=google'>color(text)=blue</a>
    // for brand, it'd look like <a href="gcs.jsp?restrictBy=color(text)=blue'>brand=google</a>
    // (no, i didn't mix up the two lines above)

    if (restrictBy <> "") then
        attribute_list = split(restrictBy,",")
        For i = 0 To ubound(attribute_list)
           attrib = attribute_list(i)
           a = split(attrib,"=")
           akey = a(0)
           avalue = escapeShoppingAPI(DEC(a(1)))
           dim other_filters 
           other_filters = ""
           for j=0 to ubound(attribute_list)
             attrib2 = attribute_list(j)
             //Response.Write (attrib + "----" + attrib2 + "<br/>")
             if (attrib <> attrib2) then
               b = split(attrib2,"=")
               bkey = b(0)
               bvalue = escapeShoppingAPI(DEC(b(1)))
               if (other_filters <> "") then
                other_filters = other_filters + "," + bkey + "=" + b(1)
               else
                 other_filters = "restrictBy=" + bkey + "=" + b(1)
               end if 
             end if
           next
          remove_filters = remove_filters + "<a href='gcs.asp?" + other_filters + q + startIndex + "'>" + akey + "=" + avalue  + "</a>&nbsp;&nbsp;&nbsp;"
        next
    end if 

    // now extract out each result 
    Set entries = xmlDoc.selectNodes("//feed/entry/s:product")

    //arrays to hold all the other attribute keys and values
    dim kk() 
    dim vv()

    For Each entry In entries
       dim stitle
	   dim slink
	   dim simage_link
	   dim sprice
       dim spid

       redim kk(0)
       redim vv(0)

       for each ni in entry.ChildNodes
            if (ni.nodeName = "s:title") then
                stitle = ni.Text
            elseif (ni.NodeName = "s:link") then
                slink = ni.Text
            elseif (ni.NodeName = "s:providedId") then
                spid = ni.Text
            elseif (ni.NodeName = "s:images") then
                for each nili in ni.ChildNodes 
                  simage_link = nili.getAttribute("link")
                Next
            elseif (ni.NodeName = "s:inventories") then
                for each nili in ni.ChildNodes
                    if nili.NodeName="s:inventory" then
                        for each p in nili.ChildNodes
                          if p.NodeName="s:price" then
                                sprice = p.Text
                          end if
                        next
                    end if
                Next
            else
               redim preserve kk(ubound(kk)+1)
               redim preserve vv(ubound(vv)+1)
               kk(ubound(kk)) = ni.NodeName
               vv(ubound(vv)) = ni.Text
            end if
       Next
       // random variable to hold the hidden div for the 'show/hide' button
               Dim pChar, pCount
               pChar = "ABCDEFGHIJKLMNPQRSTUVWXYZ0123456789"
               pCount = Len(pChar)   
               Dim div_id
               Randomize
               For i = 1 To 8
                  div_id = div_id & Mid( pChar, 1 + Int(Rnd * pCount), 1 )
               Next

               // now display the result
               dim strout
			   strout =  "<img height=100 width=100 src='"+simage_link+"'/>"+"<br/><a href='"+slink+"'>"+stitle+"</a><br/> price: " + sprice + "<br/>"
  			   strout = strout + "<div id='" + div_id + "' style='display:none'>"
			   strout = strout + "<table width='100%'>"

               for ccounter = 1 to UBound(kk)
				  strout = strout + "<tr><td>[" + kk(ccounter) + " = " + vv(ccounter) +"]</td></tr>"
			   Next
			   strout =  strout + "</table>"
               // create the button with the random div_id:
               strout = strout +  "</div><p><button type='button' onclick=" + chr(34) + "showhide('" + div_id + "','" + spid + "');" + chr(34) + ">Show/Hide detail</button></p><br/>"    
			   html_results = html_results + strout + "<hr>"      
    Next

   // now for the attributes on the left hand side
    Set facets = xmlDoc.selectNodes("//feed/s:facets/s:facet")

    For Each facet In facets
    // each facet can be either a property or attribute:
    // http://code.google.com/apis/shopping/search/v1/reference-request-parameters.html#properties
 
       dim is_property
       is_property = false
       name =  facet.getAttribute("name")
       // check to see if we have a property or attribute given the name
       if (name="price" or name="category" or name="brand") then
            is_property=true
            html_attributes = html_attributes + "<font color='blue'>" + name + "</font><br/>"
       end if
       // check to see if we have a property thats called out as one:
       // eg:  <s:facet displayName="price" property="price" count="322">
       prop =  facet.getAttribute("property")
       if not isnull(prop) then
        name = prop
        is_property=true
        // display a property as green
         html_attributes = html_attributes + "<font color='green'>" + prop + "</font><br/>"         
       end if
       
       // now extract out if its a float|int with a unit value
       stype = facet.getAttribute("type")
       unit = facet.getAttribute("unit")
       if not is_property then
         if  isnull(unit) then
             html_attributes = html_attributes  + name + "(" + stype + ")" + "<br/>"
         else
             html_attributes = html_attributes  + name + "(" + stype + ")/" + unit +  "<br/>"
         end if
       end if

    // extract out all the restricts defined earlier:
    priorRestricts = ""
    if (restrictBy <> "") then
        priorRestricts = restrictBy + ","
    end if

    // now parse the buckets.
    // if its int|float, it may look like:
    //<s:facet displayName="width" name="width" type="float" unit="inches" count="20514">
    //<s:bucket max="5.0" maxExclusive="true" count="7"/>
    //<s:bucket min="5.0" minExclusive="false" max="6.0" maxExclusive="true" count="19778"/>

        set buckets = facet.getElementsByTagName("s:bucket")
        for each bucket in buckets
           value = bucket.getAttribute("value")
           if (isnull(value)) then
                 min = bucket.getAttribute("min")
                 max = bucket.getAttribute("max")
                 minexclusive = bucket.getAttribute("minExclusive")
                 maxexclusive = bucket.getAttribute("maxExclusive")

                 if (isnull(min)) then
                    min = "0"
                 end if
                 if (isnull(max)) then
                    max = "*"
                 end if

                 if (isnull(minexclusive)) then
                    minexclusive = "["
                 else
                    if (minexclusive = "true") then
                        minexclusive = "("
                    else
                        minexclusive = "["
                    end if
                 end if

                 if (isnull(maxexclusive)) then
                    maxexclusive = "]"
                 else
                    if (maxexclusive = "true") then
                        maxexclusive = ")"
                    else
                        maxexclusive = "]"
                    end if
                 end if                 
                 xcount = bucket.getAttribute("count")
                 txt = minexclusive + min + "," + max + maxexclusive 

                 if (is_property) then
                     if (isnull(unit)) then
                         html_attributes = html_attributes + "&nbsp;&nbsp;<a href='gcs.asp?"  + "restrictBy=" + priorrestricts +  name + "=" + ENC(txt) + q +"'>" + txt + "&nbsp;&nbsp;(" + xcount + ")" + "</a><br/>"
                     else
                         html_attributes = html_attributes + "&nbsp;&nbsp;<a href='gcs.asp?" + "restrictBy=" + priorrestricts +  name + "=" + ENC(txt) + q + "'>" + txt + "&nbsp;&nbsp;(" + xcount + ")" + "</a><br/>"
                     end if
                 else
                     if (isnull(unit)) then
                         html_attributes = html_attributes + "&nbsp;&nbsp;<a href='gcs.asp?"  + "restrictBy=" + priorrestricts +  name + "(" + stype + ")" + "=" + ENC(txt) + q +"'>" + txt + "&nbsp;&nbsp;(" + xcount + ")" + "</a><br/>"
                     else
                         html_attributes = html_attributes + "&nbsp;&nbsp;<a href='gcs.asp?" + "restrictBy=" + priorrestricts +  name + "(" + stype + ")/" + unit + "=" + ENC(txt) + q + "'>" + txt + "&nbsp;&nbsp;(" + xcount + ")" + "</a><br/>"
                     end if
                 end if 

           else
               // otherwise, the buck is:
               // <s:facet displayName="category name" name="category name" type="text" count="67479">
               // <s:bucket value="California" count="20515"/>

                    txt = value + "&nbsp;(" + bucket.getAttribute("count") + ")"
                    if (is_property) then
                        html_attributes = html_attributes + "&nbsp;&nbsp;<a href='gcs.asp?" + "restrictBy=" + priorrestricts + name + "=" + ENC(value) + q + "'>" + txt  + "</a><br/>"
                    else
                        html_attributes = html_attributes + "&nbsp;&nbsp;<a href='gcs.asp?" + "restrictBy=" + priorrestricts + name + "(" + stype + ")=" + ENC(value) + q + "'>" + txt  + "</a><br/>"
                    end if
           end if
        next
    Next

// HACK:  some simple encoding of some common caracters to escape:
// it gets too convoluted to accomodate the way ',' and '&' can be inside
// and attribute value
// so..encode all &--><> and ,-->~
function ENC(str)
    ENC = Replace(Replace(str,"&","<>"),",","~")
end function

// revert back all *-->~ and ~-->,
function DEC(str)
    DEC = Replace(Replace(str,"~",","),"<>","&")
end function


Function escapeShoppingAPI(value)
// escape function for the shoppingAPI.
// the only time we don't want to escape is if we get a float number which already has a comma:
// eg. dont' escape: price=(1,10]

  if ( (Right(value,1) = ")") or (Right(value,1) = "]") ) then

  else
                    // the characters (, ), /, =, :, |, ,, ~ and \ must be escaped with the character \.
                    value = Replace(value,"(","\(")
                    value = Replace(value,")","\)")
                    value = Replace(value,"/","\/")
                    value = Replace(value,"=","\=")
                    value = Replace(value,":","\:")
                    value = Replace(value,"|","\|")
                    value = Replace(value,",","\,")
                    value = Replace(value,"~","\~")
                    value = Replace(value,"\","\\")
                    value = Replace(value, "&","%26")
    end if
  escapeShoppingAPI = value

end function


     %>


<body onload="initialize();sendRequestID('<%=requestID%>');">

<center>
	<img src="http://www.google.com/intl/en/images/logos/commerce_search_logo.gif" alt="Google Commerce Search"/>
    <form id="searchForm" method="GET">
	    <table>
    		<tr><td>search:</td><td><input id="q" name="q" type="text" size="45%" autocomplete="off" /></td></tr>     
		</table>	    
	    
		<input type="submit" value="Submit" "/>	
    </form>	
    
	<script type="text/javascript">

	    var searchText = document.getElementById('q');

	    var cx = '<%=cx%>';
	    var key = '<%=devkey%>';

	    google.load('search', '1');
	    googleapis.load('shopping', 'v1');

	    var params = {
	        country: '<%=country%>',
	        language: '<%=language%>',
	        currency: null,
	        extra_params: {
	            safe: false
	        }
	    };

	    sayt = saytInitialize(cx, key, params);
	    google.setOnLoadCallback(function () {
	        google.search.CustomSearchControl.attachAutoCompletion(
		cx, searchText, 'searchForm', sayt.saytSubmit);
	    });
		</script>
</center>

<div style="border: 0px solid rgb(0, 0, 0); width: 80%;  overflow: auto;"  id="filters" name="filters">Filters: <%=remove_filters%></div>
<br/>
<td>Total Results:  <%=totalResults%></td>
<script src="http://www.google.com/jsapi" type="text/javascript"></script><td>Page:  <%=page_nav%></td>

<hr/>
		<table width="100%" border=2>
		<tr align="top" >

		  <td width="25%" id="attributes" name="attributes"  valign="top"><b><u>Attributes</u></b><br/><%=html_attributes%></td>

		  <td width="75%" id="results" name="results"  valign="top" ><b><u>Results</u></b><br/><%=html_results%></td>
		</tr>
		</table>

<font size="1px">
	<li><font color="blue">ShoppingAPI: </font> <a href='<%=outbound_shopping%>&prettyprint=true'><%=outbound_shopping%></a></li>
	<li>RequestId: <%=requestID%></li>
	<li><font color="red">Time taken: <%=time_taken%> ms</font></li>
</font>

</body>



</html>

